//
// Created by hjie on 23-6-22.
//

#include "connection_data.h"
#include "protocol//msg_key.h"
#include "server_manager.h"
#include "room_manager.h"
#include "connection_data_room.h"
#include <rapidjson/stringbuffer.h>
#include <rapidjson/writer.h>

ConnectionData::ConnectionData(ConnectionDataRoom *room)
{
    m_room = nullptr;
    m_heart_time = time(nullptr);
}

ConnectionData::~ConnectionData()
{
    printf("~ConnectionData user id : %s.\n", m_user_name.c_str());
}

void ConnectionData::Destroy()
{
    if (!m_room || m_user_name.empty())
    {
        return;
    }
    m_room->m_room_thread_msg_queue->PushTask([this](){

        if (m_room)
        {
            std::string user_name = m_user_name;
            auto room        = m_room;
            auto connection  = this;
            room->m_room_thread_msg_queue->PushTask([connection, room, user_name](){

                if (!user_name.empty())
                {
                    rapidjson::Document out(rapidjson::kObjectType);
                    hnhj::AddObjectMember(out, header_k);
                    hnhj::AddStringMember(out[header_k], out.GetAllocator(), msg_type_k, user_out_k);
                    hnhj::AddStringMember(out[header_k], out.GetAllocator(), user_id_k, user_name);
                    hnhj::AddStringMember(out[header_k], out.GetAllocator(), room_id_k, room->RoomId());
                    hnhj::AddObjectMember(out, content_k);

                    room->ProcessMessageProtocol(connection, out);
                }
                delete connection;
            });
        }
    });
}

void ConnectionData::UpdateTime()
{
    m_heart_time = time(nullptr);
}

void ConnectionData::HeartBeat()
{
    rapidjson::Document heart_beat(rapidjson::kObjectType);
    heart_beat.AddMember(header_k, rapidjson::Value(rapidjson::kObjectType), heart_beat.GetAllocator());
    heart_beat.AddMember(content_k, rapidjson::Value(rapidjson::kObjectType), heart_beat.GetAllocator());

    std::string room_id = m_room->RoomId();
    heart_beat[header_k].AddMember(msg_type_k, rapidjson::Value().SetString(heart_beat_k, heart_beat.GetAllocator()), heart_beat.GetAllocator());
    heart_beat[header_k].AddMember(room_id_k, rapidjson::Value().SetString(room_id.c_str(), room_id.size(), heart_beat.GetAllocator()), heart_beat.GetAllocator());
    heart_beat[header_k].AddMember(user_id_k, rapidjson::Value().SetString(m_user_name.c_str(), m_user_name.size(), heart_beat.GetAllocator()), heart_beat.GetAllocator());
    heart_beat[header_k].AddMember(result_k, 0, heart_beat.GetAllocator());
    int64_t now_time = time(nullptr);
    heart_beat[content_k].AddMember(timestamp_k, now_time, heart_beat.GetAllocator());
    rapidjson::StringBuffer s;
    rapidjson::Writer<rapidjson::StringBuffer> writer(s);
    heart_beat.Accept(writer);

    if (m_socket && !m_socket->isClosed())
    {
        m_socket->send(s.GetString());
    }
}

void ConnectionData::ProcessData(std::string * content, int op)
{
    if (m_room)
    {
        m_room->m_room_thread_msg_queue->PushTask([this, content](){

            std::unique_ptr<std::string> guard(content);
            rapidjson::Document input;
            if (input.Parse(content->c_str(), content->size()).HasParseError())
            {

            }
            else
            {
                m_room->ProcessMessageProtocol(this, input);
            }
        });
    }
    else
    {
        auto * input = new rapidjson::Document();
        if (!input->Parse(content->c_str(), content->size()).HasParseError())
        {
            if (input->HasMember(header_k) && (*input)[header_k].IsObject() &&
                    (*input)[header_k].HasMember(msg_type_k) && (*input)[header_k][msg_type_k].IsString() &&
                    (*input)[header_k].HasMember(room_id_k)  && (*input)[header_k][room_id_k].IsString())
            {
                std::string msg_type = (*input)[header_k][msg_type_k].GetString();
                std::string room_id  = (*input)[header_k][room_id_k].GetString();
                if (room_id.empty())
                {
                    m_socket->close();
                    std::unique_ptr<std::string> guard(content);
                    return;
                }
                if (msg_type == user_in_req_k)
                {
                    m_room = ServerManager::Instance()->m_room_manager->AddRoom(room_id);
                    if (m_room)
                    {
                        m_room_id = room_id;
                        m_room->m_room_thread_msg_queue->PushTask([this, input](){

                            std::unique_ptr<rapidjson::Document> guard(input);
                            m_room->ProcessMessageProtocol(this, *input);
                        });
                    }
                }
            }
        }
        delete content;
        content = nullptr;
    }
}

void ConnectionData::ProcessData(const char *msg, int size, int op)
{
    auto * message = new std::string();
    message->assign(msg, size);
    printf("recv msg : %s from %s:%d\n", message->c_str(), m_socket->getAddress().address, m_socket->getAddress().port);
    ProcessData(message, op);
}